#include "myiic.h"
#include "delay.h"

#include "stm32f1xx_hal.h"

#define IIC_SCL_GPIO_PORT GPIOB
#define IIC_SCL_GPIO_PIN  GPIO_PIN_4
#define IIC_SCL_GPIO_CLK_ENABLE()     \
    do {                              \
        __HAL_RCC_GPIOB_CLK_ENABLE(); \
    } while (0)

#define IIC_SDA_GPIO_PORT GPIOB
#define IIC_SDA_GPIO_PIN  GPIO_PIN_3
#define IIC_SDA_GPIO_CLK_ENABLE()     \
    do {                              \
        __HAL_RCC_GPIOB_CLK_ENABLE(); \
    } while (0)


#define IIC_SCL(x)                                                                  \
    do {                                                                            \
        x ? HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET)    \
          : HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
    } while (0)
#define IIC_SDA(x)                                                                  \
    do {                                                                            \
        x ? HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET)    \
          : HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
    } while (0)


#define IIC_READ_SDA() HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)

static void iic_delay(void)
{
    delay_us(2);
}

void iic_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    IIC_SCL_GPIO_CLK_ENABLE();
    IIC_SDA_GPIO_CLK_ENABLE();

    GPIO_InitStruct.Pin   = IIC_SCL_GPIO_PIN;
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull  = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin  = IIC_SDA_GPIO_PIN;
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &GPIO_InitStruct);

    iic_stop();
}

void iic_start(void)
{
    IIC_SDA(1);
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

void iic_stop(void)
{
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);
    iic_delay();
}

void iic_send_byte(uint8_t data)
{
    uint8_t t;
    for (t = 0; t < 8; t++) {
        IIC_SDA((data & 0x80) >> 7);
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        iic_delay();
        data <<= 1;
    }
    IIC_SDA(1);
}

uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;
    for (i = 0; i < 8; i++) {
        receive <<= 1;
        IIC_SCL(1);
        iic_delay();
        if (IIC_READ_SDA()) {
            receive++;
        }
        IIC_SCL(0);
        iic_delay();
    }
    if (!ack) {
        iic_nack();
    }
    else {
        iic_ack();
    }
    return receive;
}

uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack     = 0;

    IIC_SDA(1);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    while (IIC_READ_SDA()) {
        waittime++;
        if (waittime > 250) {
            iic_stop();
            rack = 1;
            break;
        }
    }
    // if (IIC_READ_SDA()) {
    //     rack = 1;
    // }
    IIC_SCL(0);
    iic_delay();
    return rack;
}

void iic_ack(void)
{
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);
    iic_delay();
}


void iic_nack(void)
{
    IIC_SDA(1);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

uint8_t iic_check_device(uint8_t slave_addr)
{
    uint8_t ack;

    iic_init();

    iic_start();
    iic_send_byte((slave_addr << 1) | 0);
    ack = iic_wait_ack();
    iic_stop();

    return ack;
}
